#!/usr/bin/env python
#
# Original author: Jader Dias
# Project Page: http://code.google.com/p/authfeed
#
# Copyright (c) 2009 by Jader Dias.  Use is permitted under
# the Artistic License
# <http://www.opensource.org/licenses/artistic-license.html>
#
import cgi
import os
import re
import urllib
import urlparse
import uuid
import datetime
from datetime import timedelta, date
from urllib import quote, unquote  
from google.appengine.ext.webapp import template
from google.appengine.api import users, urlfetch
from google.appengine.ext import webapp, db
from google.appengine.ext.webapp.util import run_wsgi_app

def format_date(dt, rfc):
    if rfc == 3339:
	    return dt.strftime("%Y-%m-%dT%H:%M:%S")
    else:
        return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (
                ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][dt.weekday()],
                dt.day,
                ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][dt.month-1],
                dt.year, dt.hour, dt.minute, dt.second)

class Source(db.Model):
  user = db.UserProperty(auto_current_user_add=True)
  creation = db.DateTimeProperty(auto_now_add=True)
  modification = db.DateTimeProperty(auto_now=True)
  url = db.StringProperty(multiline=False)
  guid = db.StringProperty(multiline=False)
  cookie = db.TextProperty()
  title = db.StringProperty(multiline=False)
  description = db.StringProperty(multiline=False)
  item_region = db.StringProperty(multiline=False)
  item_separator = db.StringProperty(multiline=False)
  item_title = db.StringProperty(multiline=False)
  item_link = db.StringProperty(multiline=False)
  item_uuid = db.StringProperty(multiline=False)
  item_description = db.StringProperty(multiline=False)
  last_content = db.BlobProperty()

class Item(db.Model):
  creator = db.UserProperty(auto_current_user_add=True)
  creation = db.DateTimeProperty(auto_now_add=True)
  source = db.ReferenceProperty(Source, collection_name="items")
  title = db.StringProperty(multiline=False)
  description = db.StringProperty(multiline=True)
  link = db.StringProperty(multiline=False)
  guid = db.StringProperty(multiline=False)
  comments = db.StringProperty(multiline=False)
  
class MainPage(webapp.RequestHandler):
  def get(self):
    self.redirect('source');

class RequestHandlerLoginRequired(webapp.RequestHandler):
  def get(self):
    if users.get_current_user():
        self.getLoggedIn()
    else:
	    self.redirect(users.create_login_url(self.request.uri))
  def post(self):
    if users.get_current_user():
	    self.postLoggedIn()
    else:
	    self.response.out.write('login required')

class SourceView(RequestHandlerLoginRequired):
  def getLoggedIn(self):
    user = users.get_current_user()
    sources = Source().all().filter("user =", user).fetch(1000)
    template_values = {
        'sources' : sources
    }
    path = os.path.join(os.path.dirname(__file__), 'source.html')
    self.response.out.write(template.render(path, template_values))

class SourceDel(RequestHandlerLoginRequired):
  def postLoggedIn(self):
    id = self.request.get('id')
    if id:
	    source = Source.get_by_id(int(id))
	    source.delete()
    self.redirect('/source')

class SourcePut(RequestHandlerLoginRequired):
  def postLoggedIn(self):
    source = Source()
    id = self.request.get('id')
    if id:
	    source = Source.get_by_id(int(id))
    for property in self.request.arguments():
        if property != 'id':
            setattr(source, property, self.request.get(property))
    source.guid = str(uuid.uuid5(uuid.NAMESPACE_URL, quote(source.title)))
    source.put()
    self.redirect('/source')

dateFormat = "%Y-%m-%d"

class SimpleProxy(webapp.RequestHandler):
  def get(self):
    id = self.request.get('id')
    if id:
        source = Source.get_by_id(int(id))
        try:
            result = urlfetch.fetch(url = source.url,
                method = urlfetch.GET)
            source.last_content = result.content
            source.put()
            self.response.out.write(result.content)
        except urlfetch.DownloadError:
            self.response.out.write(source.last_content)
    else:
        self.response.out.write('invalid id')

class ProxyHandler(webapp.RequestHandler):
  def get(self):
    id = self.request.get('id')
    if id:
        self.source = Source.get_by_id(int(id))
        url = self.source.url % ((date.today() - timedelta(days=59)).strftime(dateFormat), date.today().strftime(dateFormat))
        self.result = urlfetch.fetch(url = url,
                        method = urlfetch.GET,
                        headers = {'Cookie': self.source.cookie})
        self.getResult()
    else:
        self.response.out.write('invalid id')

class Proxy(ProxyHandler):
  def getResult(self):
    self.response.out.write(self.result.content)

class FeedView(ProxyHandler):
  def getResult(self):
    source = self.source
    selection = \
        re.search(source.item_region, self.result.content).group(1)
    unparsedItems = \
        re.split(source.item_separator, selection)
    unparsedItems.reverse()
    for unparsedItem in unparsedItems:
        item = Item()
        guid_seed = re.search(source.item_uuid, unparsedItem).group(1)
        item.guid = str(uuid.uuid5(uuid.NAMESPACE_URL, quote(guid_seed)))
        if len(Item.all().filter("source =", source.key()).filter("guid =", item.guid).fetch(1)) == 0:
            relative_link = re.search(source.item_link, unparsedItem).group(1)
            item.title = re.search(source.item_title, unparsedItem).group(1)
            item.description = re.search(source.item_description, unparsedItem).group(1)
            item.link = urlparse.urljoin(source.url, relative_link)
            item.source = source
            item.put()
    items = source.items.order("-creation").fetch(10)
    template_values = {
        'source' : source,
        'items': items,
        'url' : self.request.url
      }
    view = 'rss2.0.xml'
    rfc = 822
    if self.request.get('format') == 'atom':
        view = 'atom.xml'
        rfc = 3339
    for item in items:
        item.creationString = format_date(item.creation, rfc)
    source.creationString = format_date(source.creation, rfc)
    source.modificationString = format_date(items[0].creation, rfc)
    path = os.path.join(os.path.dirname(__file__), view)
    self.response.headers.add_header('Last-Modified', format_date(items[0].creation, 822))
    self.response.headers.add_header('Etag', items[0].guid)
    self.response.out.write(template.render(path, template_values))

application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/feed', FeedView),
                                      ('/source', SourceView),
                                      ('/source/put', SourcePut),
                                      ('/source/del', SourceDel),
                                      ('/proxy', Proxy),
                                      ('/simpleproxy', SimpleProxy),
                                     ],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()
